package org.ims.inv.web.action.statistic;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.ims.inv.model.flow.ModelFlowDef;
import org.ims.inv.model.flow.ModelFlowTemplate;
import org.ims.inv.model.flow.material.ModelFlowMaterial;
import org.ims.inv.model.project.ModelProject;
import org.ims.inv.model.project.ModelProjectEvent;
import org.ims.inv.model.project.ModelProjectMaterial;
import org.ims.inv.model.project.ModelProjectMaterialMeta;
import org.ims.inv.model.project.ModelProjectProcess;
import org.ims.inv.model.system.ModelAppUser;
import org.ims.inv.vo.VoProjectData;
import org.ims.inv.web.action.project.ProjectBaseAction;
import org.ims.inv.web.util.ExcelTemplateSupport;

import cn.trymore.core.exception.ServiceException;
import cn.trymore.core.util.UtilCollection;
import cn.trymore.core.util.UtilDate;
import cn.trymore.core.util.UtilResources;
import cn.trymore.core.util.UtilString;
import cn.trymore.core.vo.VoTplExcelObj;
import cn.trymore.core.web.paging.PaginationSupport;
import cn.trymore.core.web.paging.PagingBean;

/**
 * Action: 数据统计
 * 
 * @author Jeccy.Zhao
 *
 */
public class StatisticAction
extends ProjectBaseAction
{
	/**
	 * The LOGGER
	 */
	private static final Logger LOGGER = Logger.getLogger(StatisticAction.class);
	
	/**
	 * The file upload destination path.
	 */
	private String uploadPath = "";
	
	/**
	 * The file upload temporary path.
	 */
	private String tempPath = "";
	
	/**
	 * 数据初始化
	 * 
	 * @param request
	 */
	private void init (HttpServletRequest request)
	{
		try
		{
			// 加载流程环节模板
			ModelFlowDef activatedDef = 
				this.serviceWorkFlow.getServiceFlowDefinition().getCurrentAppliedDefinition();
			if (activatedDef != null)
			{
				request.setAttribute("processes", activatedDef.getTemplates());
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when initia data.", e);
		}
	}
	
	/**
	 * 初始化文件夹
	 */
	private void initFolders ()
	{
		this.uploadPath = UtilResources.getWebRootPath() + "uploads";
		
		File localFile = new File(this.uploadPath);
		if (!localFile.exists())
		{
			localFile.mkdirs();
		}
		
		this.tempPath = this.uploadPath + "/temp";
		File tmpFile = new File(this.tempPath);
		if (!tmpFile.exists())
		{
			tmpFile.mkdirs();
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 按项目统计
	 */
	public ActionForward pageByProjectIndex (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			init(request);
			
			loadProjectRowData(form, request);
			
			return mapping.findForward("page.statistic.project.index");
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 按人数统计
	 */
	public ActionForward pageByPersonIndex (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			init(request);
			
			ModelProject formEntity = (ModelProject) form;
			
			// 项目负责人
			String projectManagerName = request.getParameter("mgr.username");
			if (UtilString.isNotEmpty(projectManagerName))
			{
				String projectManagerId = request.getParameter("mgr.id");
				ModelAppUser manager = new ModelAppUser();
				manager.setUsername(projectManagerName);
				manager.setId(projectManagerId);
				formEntity.setProjectManager(manager);
				
				formEntity.setRelevantPersonIncluded(true);
			}
			
			// 项目登记人
			String projectRecorderName = request.getParameter("recorder.username");
			if (UtilString.isNotEmpty(projectRecorderName))
			{
				ModelAppUser recorder = new ModelAppUser();
				recorder.setUsername(projectRecorderName);
				formEntity.setProjectRecorder(recorder);
			}
			
			if (formEntity.getCondVO() != null && 
					!UtilString.isNotEmpty(formEntity.getCondVO().getCondProjectYear()))
			{
				// 默认设置为当前年份
				formEntity.getCondVO().setCondProjectYear(UtilDate.parseTime(new Date(), "yyyy"));
			}
			
			List<ModelProject> projects = 
				this.serviceProject.getProjectsByCriterion(formEntity);
			
			request.setAttribute("datagrid", 
					this.categorizeByPerson(projects, formEntity.getProjectManager()));
			
			request.setAttribute("formEntity", formEntity);
			
			this.outWriteAllParameters(request);
			
			return mapping.findForward("page.statistic.person.index");
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 按进度统计
	 */
	public ActionForward pageByProgressIndex (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			init(request);
			
			loadProjectRowData(form, request);
			
			return mapping.findForward("page.statistic.progress.index");
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 按材料统计
	 */
	public ActionForward pageByMaterialIndex (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			init(request);
			
			loadProjectRowData(form, request);
			
			request.setAttribute("materialTypes", 
					this.serviceWorkFlow.getServiceFlowMaterial().getAllRootMaterials());
			
			return mapping.findForward("page.statistic.material.index");
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * 加载项目列表数据
	 * 
	 * @param form
	 * @param request
	 * @throws ServiceException
	 */
	private void loadProjectRowData (ActionForm form, 
			HttpServletRequest request) throws ServiceException
	{
		ModelProject formEntity = (ModelProject) form;
		
		// 项目负责人
		String projectManagerName = request.getParameter("mgr.username");
		if (UtilString.isNotEmpty(projectManagerName))
		{
			ModelAppUser manager = new ModelAppUser();
			manager.setUsername(projectManagerName);
			formEntity.setProjectManager(manager);
		}
		
		// 项目登记人
		String projectRecorderName = request.getParameter("recorder.username");
		if (UtilString.isNotEmpty(projectRecorderName))
		{
			ModelAppUser recorder = new ModelAppUser();
			recorder.setUsername(projectRecorderName);
			formEntity.setProjectRecorder(recorder);
		}
		
		PagingBean pagingBean = this.getPagingBean(request);
		PaginationSupport<ModelProject> pagingData = this.serviceProject.getPagination(formEntity, pagingBean);
		
		request.setAttribute("datagrid", pagingData);
		request.setAttribute("formEntity", formEntity);
		
		this.outWritePagination(request, pagingBean, pagingData);
		this.outWriteAllParameters(request);
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 材料一览
	 */
	public ActionForward dialogMaterialList (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		String projectId = request.getParameter("pid");
		try
		{
			if (UtilString.isNotEmpty(projectId))
			{
				ModelProject project = this.serviceProject.get(projectId);
				if (project != null)
				{
					if (request.getParameter("mandatory") != null)
					{
						// 必须材料
						request.setAttribute("datagrid", 
								project.getMandatoryMaterialList(true));
					}
					else
					{
						String templateMaterialId = request.getParameter("tid");
						if (!UtilString.isNotEmpty(templateMaterialId))
						{
							return ajaxPrint(response, getErrorCallback("未知的请求参数."));
						}
						
						// 材料分类
						ModelFlowMaterial templateMaterial = 
							this.serviceWorkFlow.getServiceFlowMaterial().get(templateMaterialId);
						
						if (templateMaterial == null)
						{
							return ajaxPrint(response, getErrorCallback("材料数据实体不存在."));
						}
						
						Set<ModelProjectMaterial> materials = project.getMaterials();
						if (UtilCollection.isNotEmpty(materials))
						{
							for (ModelProjectMaterial material : materials)
							{
								if (material.getMaterialName().equals(templateMaterial.getMaterialName()))
								{
									request.setAttribute("datagrid", 
										this.convertToMaterialMetaList(material));
									break;
								}
							}
						}
					}
					
					return mapping.findForward("dialog.statistic.material.list");	
				}
				else
				{
					return ajaxPrint(response, getErrorCallback("项目数据实体不存在."));
				}
			}
			else
			{
				return ajaxPrint(response, getErrorCallback("未知的请求参数."));
			}
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, getErrorCallback("数据加载失败,原因:" + e.getMessage()));
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 项目一览导出
	 */
	public ActionForward actionExportByProjects (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			init(request);
			
			// 初始化文件夹
			initFolders();
			
			// 获取数据
			List<ModelProject> result = this.serviceProject.getByCriterion((ModelProject)form);
			
			if (UtilCollection.isNotEmpty(result))
			{
				VoTplExcelObj obj = ExcelTemplateSupport.getTplObjFromTplFile(
						ExcelTemplateSupport.XLS_TPL_PATH + "/excel.statistic.by.project.xml", null);
				
				if (obj != null)
				{
					List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
					for (ModelProject project : result)
					{
						VoProjectData row = this.convertFromProject(project);
						if (row != null)
						{
							Map<String, Object> singleRow = new HashMap<String, Object>();
							singleRow.put("project", row);
							data.add(singleRow);
						}
					}
					
					obj = ExcelTemplateSupport.fillTplData(obj, data, null);
					obj.setSheetName("项目一览");
					
					String fileName = "exportByProject_" + UtilDate.parseTime(new Date(), "yyyyMMddHHmmssSS") + ".xls";
					ExcelTemplateSupport.createExcel(this.tempPath + "/" + fileName, obj);
					
					return ajaxPrint(response, "{status:200, file:'" + "temp/" + fileName + "', name:'" + fileName + "'}");
				}
			}
			
			return ajaxPrint(response, "{status:500, message:'文件导出失败'}");
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, "{status:500, message:'文件导出失败.'}");
		}
	}
	
	/**
	 * <b>[WebAction]</b> 
	 * <br/>
	 * 项目进度导出
	 */
	@SuppressWarnings("unchecked")
	public ActionForward actionExportByProgress (ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) 
	{
		try
		{
			init(request);
			
			// 初始化文件夹
			initFolders();
			
			// 获取数据
			List<ModelProject> result = this.serviceProject.getByCriterion((ModelProject)form);
			
			if (UtilCollection.isNotEmpty(result))
			{
				List<Map<String, Object>> preData = new ArrayList<Map<String,Object>>();
				if (request.getAttribute("processes") != null)
				{
					Set<ModelFlowTemplate> tpls = (Set<ModelFlowTemplate>)request.getAttribute("processes");
					if (UtilCollection.isNotEmpty(tpls))
					{
						for (ModelFlowTemplate tpl : tpls)
						{
							Map<String, Object> singleData = new HashMap<String, Object>();
							singleData.put("proc", tpl);
							preData.add(singleData);
						}
					}
				}
				
				VoTplExcelObj obj = ExcelTemplateSupport.getTplObjFromTplFile(
						ExcelTemplateSupport.XLS_TPL_PATH + "/excel.statistic.by.progress.xml", preData);
				
				if (obj != null)
				{
					List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();
					for (ModelProject project : result)
					{
						VoProjectData row = this.convertFromProject(project);
						if (row != null)
						{
							Map<String, Object> singleRow = new HashMap<String, Object>();
							singleRow.put("project", row);
							data.add(singleRow);
						}
					}
					
					obj = ExcelTemplateSupport.fillTplData(obj, data, null);
					obj.setSheetName("进度一览");
					
					String fileName = "exportByProgress_" + UtilDate.parseTime(new Date(), "yyyyMMddHHmmssSS") + ".xls";
					ExcelTemplateSupport.createExcel(this.tempPath + "/" + fileName, obj);
					
					return ajaxPrint(response, "{status:200, file:'" + "temp/" + fileName + "', name:'" + fileName + "'}");
				}
			}
			
			return ajaxPrint(response, "{status:500, message:'文件导出失败'}");
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when loading page", e);
			return ajaxPrint(response, "{status:500, message:'文件导出失败.'}");
		}
	}
	
	/**
	 * 转换成导出数据格式
	 * 
	 * @param entity
	 * @return
	 */
	private VoProjectData convertFromProject (ModelProject entity)
	{
		if (entity != null)
		{
			VoProjectData data = new VoProjectData();
			
			data.setProjectNo(entity.getProjectNo());
			data.setProjectName(entity.getProjectName());
			data.setProjectPartnerName(entity.getProjectPartnerName());
			data.setProjectSummary(entity.getProjectSummary());
			
			String attendees = entity.getProjectAttendeeIds();
			if (UtilString.isNotEmpty(attendees))
			{
				List<String> attendeeNames = new ArrayList<String>();
				String[] lstId = attendees.split(",");
				for (String uid : lstId)
				{
					try
					{
						if (UtilString.isNotEmpty(uid))
						{
							ModelAppUser user = this.serviceAppUser.get(uid);
							if (user != null)
							{
								attendeeNames.add(user.getUsername());
							}
						}
					}
					catch (Exception e)
					{
						LOGGER.error("Entity can not be found with id:" + uid, e);
					}
				}
				
				data.setProjectParticipant(UtilString.join(attendeeNames, ","));
			}
			
			if (entity.getCurrentProcess() == null && 
					entity.getProjectStatus().equals(ModelProject.EProjectStatus.APPROVING.getValue()))
			{
				data.setProjectProgress("项目分配");
				data.setProjectStatus("待分配");
			}
			else if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.APPROVED.getValue()) || 
					entity.getProjectStatus().equals(ModelProject.EProjectStatus.REJECTED.getValue()))
			{
				data.setProjectProgress("审批结束");
				data.setProjectStatus("审批结束");
			}
			else if (entity.getCurrentProcess() != null)
			{
				data.setProjectProgress(entity.getCurrentProcess().getNodeTitle());
			}
			else 
			{
				data.setProjectProgress("---");
			}
			
			data.setProjectManager(entity.getProjectManager().getUsername());
			
			if (entity.getProjectReferral() != null)
			{
				data.setProjectReferral(entity.getProjectReferral().getUsername());
			}
			
			if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.TOPOST.getValue()))
			{
				data.setProjectStatus("材料待提交");
			}
			else if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.APPROVING.getValue()))
			{
				data.setProjectStatus("审批中");
			}
			else if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.RETURNED.getValue()))
			{
				data.setProjectStatus("审批退回");
			}
			else if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.SUSPENDED.getValue()))
			{
				data.setProjectStatus("已暂停");
				data.setProjectProgress("审批结束");
			}
			
			data.setProjectType(entity.getProjectType().getDictKey());
			data.setProjectIntroduceTime(UtilDate.parseTime(entity.getProjectRecommendedDate(), "yyyy-MM-dd"));
			data.setProjectSubmitTime(UtilDate.parseTime(entity.getProjectCreationTime(), "yyyy-MM-dd"));
			
			if (entity.getProjectRecorder() != null)
			{
				data.setProjectRecorder(entity.getProjectRecorder().getUsername());
			}
			
			if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.APPROVED.getValue()))
			{
				data.setProjectAuditState("通过");
			}
			else if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.REJECTED.getValue()))
			{
				data.setProjectAuditState("否决");
			}
			else if (!entity.getProjectStatus().equals(ModelProject.EProjectStatus.SUSPENDED.getValue()))
			{
				data.setProjectAuditState("审批中");
			}
			else
			{
				data.setProjectAuditState("---");
			}
			
			
			String[] progStatus = new String[entity.getProcessForms().size()];
			String[] progSubmitTime = new String[entity.getProcessForms().size()];
			String[] progAuditTime = new String[entity.getProcessForms().size()];
			int count = 0;
			for (ModelProjectProcess proc : entity.getProcessForms())
			{
				if (proc.getAuditState() != null)
				{
					if (proc.getAuditState().equals(ModelProjectProcess.EProjectAuditState.PASS.getValue()))
					{
						progStatus[count] = "已通过";
					}
					else if (proc.getAuditState().equals(ModelProjectProcess.EProjectAuditState.IGNORED.getValue()))
					{
						progStatus[count] = "已跳过";
					}
					else if (proc.getAuditState().equals(ModelProjectProcess.EProjectAuditState.REJECTED.getValue()))
					{
						progStatus[count] = "已否决";
					}
					else
					{
						progStatus[count] = "";
					}
					
					// 提交时间
					ModelProjectEvent submitEvent = obtainProjectEvent(entity.getId(), null, 
							"提交至`" + proc.getNodeTitle() + "`", null);
					if (submitEvent != null)
					{
						progSubmitTime[count] = UtilDate.parseTime(submitEvent.getEventTime());
					}
					else
					{
						progSubmitTime[count] = "";
					}
					
					// 审批时间
					ModelProjectEvent auditEvent = obtainProjectEvent(entity.getId(), 
							ModelProjectProcess.EProjectAuditState.PASS.getValue(), null, proc.getNodeTitle());
					if (auditEvent != null)
					{
						progAuditTime[count] = UtilDate.parseTime(auditEvent.getEventTime());
					}
					else
					{
						progAuditTime[count] = "";
					}
				}
				else
				{
					progStatus[count] = "";
					progSubmitTime[count] = "";
					progAuditTime[count] = "";
				}
				
				count++;
			}
			
			data.setProjectProgStatus(progStatus);
			data.setProjectProgSubmitTime(progSubmitTime);
			data.setProjectProgAuditTime(progAuditTime);
			
			if (entity.getProjectStatus().equals(ModelProject.EProjectStatus.SUSPENDED.getValue()))
			{
				data.setProjectSuspendStatus("已暂停");
			}
			else
			{
				data.setProjectSuspendStatus("---");
			}
			
			return data;
		}
		
		return null;
	}
	
	/**
	 * 获取项目事件
	 * 
	 * @param projectId
	 * @param state
	 * @param text
	 * @param eventName
	 * 
	 * @return
	 */
	private ModelProjectEvent obtainProjectEvent (String projectId, 
			Integer state, String text, String eventName)
	{
		try
		{
			ModelProjectEvent entity = new ModelProjectEvent();
			ModelProject project = new ModelProject();
			project.setId(projectId);
			
			entity.setProject(project);
			entity.setEventComments(text);
			entity.setEventName(eventName);
			
			if (state != null)
			{
				entity.setEventState(state);
			}
			
			List<ModelProjectEvent> events = this.serviceProjectEvent.getByCriterion(entity);
			if (events != null && events.size() > 0)
			{
				return events.get(0);
			}
			
			return null;
		}
		catch (Exception e)
		{
			LOGGER.error("Exception raised when obtaining project event.", e);
			return null;
		}
	}
	
	/**
	 * 转换成材料列表
	 * 
	 * @param material
	 * @return
	 */
	private List<ModelProjectMaterial> convertToMaterialMetaList (
			ModelProjectMaterial material)
	{
		if (material != null)
		{
			List<ModelProjectMaterial> list = new ArrayList<ModelProjectMaterial>();
			
			ModelProjectMaterialMeta latestMetaData = material.getLatestUploadMeta();
			if (latestMetaData != null)
			{
				list.add(material);
			}
			
			if (UtilCollection.isNotEmpty(material.getMaterialChildren()))
			{
				for (ModelProjectMaterial subNode : material.getMaterialChildren())
				{
					ModelProjectMaterialMeta meta = subNode.getLatestUploadMeta();
					if (meta != null)
					{
						list.add(subNode);
					}
				}
			}
			
			return list;
		}
		return null;
	}
	
	
	/**
	 * 根据人员进行项目归类
	 * 
	 * @param projects
	 * @param filterUser
	 * @return
	 * @throws ServiceException 
	 */
	private Map<String, Map<Long, List<ModelProject>>> categorizeByPerson (
			List<ModelProject> projects, ModelAppUser filterUser) throws ServiceException
	{
		if (UtilCollection.isNotEmpty(projects))
		{
			// 项目负责/参与标志
			Long catProjectOwner = 0L;
			Long catProjectParticipate = 1L;
			
			Map<String, Map<Long, List<ModelProject>>> catsByPerson = 
				new TreeMap<String, Map<Long, List<ModelProject>>>(); 
			
			for (ModelProject project : projects)
			{
				List<String> relevantPersonIds = project.getRelevantPersonIds();
				
				if (project.getProjectManager() != null 
						&& !project.getProjectManager().isSuperUser() && 
						(filterUser == null || project.getProjectManager().getId().equals(filterUser.getId())))
				{
					// 统计负责人员
					String owner = project.getProjectManager().getUsername();
					if (!catsByPerson.containsKey(owner))
					{
						catsByPerson.put(owner, new TreeMap<Long, List<ModelProject>>());
					}
					
					Map<Long, List<ModelProject>> ownerData = catsByPerson.get(owner);
					if (!ownerData.containsKey(catProjectOwner))
					{
						ownerData.put(catProjectOwner, new ArrayList<ModelProject>());
					}
					
					ownerData.get(catProjectOwner).add(project);
				}
				
				// 统计参与人员
				if (UtilCollection.isNotEmpty(relevantPersonIds))
				{
					for (String uid : relevantPersonIds)
					{
						// 过滤负责人ID
						if (!uid.equals(project.getProjectManager().getId()) && 
								!uid.equals(ModelAppUser.SUPER_USER_ID) && (filterUser == null || uid.equals(filterUser.getId())))
						{
							ModelAppUser member = this.serviceAppUser.get(uid);
							if (member != null)
							{
								String memberName = member.getUsername();
								if (!catsByPerson.containsKey(memberName))
								{
									catsByPerson.put(memberName, new TreeMap<Long, List<ModelProject>>());
								}
								
								Map<Long, List<ModelProject>> rs = catsByPerson.get(memberName);
								if (!rs.containsKey(catProjectParticipate))
								{
									rs.put(catProjectParticipate, new ArrayList<ModelProject>());
								}
								
								rs.get(catProjectParticipate).add(project);
							}
						}
					}
				}
				
			}
			
			return catsByPerson;
		}
		
		return null;
	}
	
	
	public static Logger getLogger()
	{
		return LOGGER;
	}
	
	
}
